package edu.gatech.cs3240;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import edu.gatech.cs3240.GrammarChecker.UnparseableException;
import edu.gatech.cs3240.NFA.NFA;
import edu.gatech.cs3240.NFA.NFAGen;

/**
 * The group24 class reads in and evalutes the expression passed from a file.
 * @author JMitchell
 */
public class group24 {
	
  /* collections containing our own structures */
  private Scanner           scanner;
  private GrammarChecker    checker;
  
  /* variables for file IO */
  private String          filePath;
  private FileReader      reader;
  private BufferedReader  buffer;
  
  /* variables to store file contents */
  private String            regexLine;
  private ArrayList<String> evalExpressions;
  
  
  /**
	 * Constructor -- builds a "group24" object and consumes a file
	 * @param filePath the path to the file containing the regex and strings
	 */
  public group24(String filePath) {
    
    /* populate the filePath instance variable with the value passed in */
    this.filePath = filePath;
    
    /* populate ArrayLists */
    this.evalExpressions  = new ArrayList<String>();
    
    try {
      /* try to open the file */
      this.reader = new FileReader(filePath);
      this.buffer = new BufferedReader(reader);
      
      /* try and read the file */
      String currString = buffer.readLine();

      /* the first line contains the regex */
      this.regexLine    = currString;
      
      /* read the rest of the lines; these contain expressions to evaluate */
      currString = buffer.readLine();
      while(currString != null) {
        
        /* add the string to the list of strings to evaluate */
        evalExpressions.add(currString);
        
        /* read another line */
        currString = buffer.readLine();
      }
      
      /* try and close the file */
      this.reader.close();
    
    } catch(FileNotFoundException e) {
      /* the file does not exist */
      System.err.println("Error: The file " + this.filePath + " does not exist. Exiting.");
      System.exit(2);
    } catch(IOException e) {
      /* an I/O error of some sort occurred */
      System.err.println("Error: An unknown I/O error occurred. Exiting.");
      System.exit(3);
    }
  }
  
  /**
   * Executes the scanner and parser and reports the output.
   */
  public void runIt() throws UnparseableException {
	    
	    /* time to build a scanner */
	    try {
	      this.scanner = new Scanner(regexLine);
	      
	    } catch(Scanner.BadCharacterException e) {
	      /* a bad character was found */
	      System.err.println("Error: The scanner found an invalid character in the passed regular expression: '" + e.getErrorChar() + "' was found at index " + e.getErrorIndex() + ". Exiting.");
	      System.exit(4);
	    }
	    
	      this.checker = new GrammarChecker();
	      ParseTreeNode ptn = checker.parse(this.scanner);
	      System.out.println("Successful Parsinations!! Tree:");
	      System.out.println(ptn.toString());
	    
	    /* Finished parsing the regex.  Assuming there were no exceptions, 
	     * it's time to build the NFA.
	     */
	    ArrayList<ParseTreeNode> ptna = new ArrayList<ParseTreeNode>();
	    ptna.add(ptn);
	    NFA nfa = new NFAGen().createNFA(ptna);
	    System.out.println("NFA generation successful.  Output:");
	    System.out.println(nfa.toString());
	    
	    /* Done Creating the NFA it's time to check the input to see 
	     * if it's a match
	     */
	    NewStartParser p;
	    int successfulParses = 0;
	    int waitCycles;
	    System.out.println("Evaluating Strings.");
	    for(int i = 0; i < evalExpressions.size(); i++) {
		    // System.out.print("***" + evalExpressions.get(i) + "***");
	    	p = new NewStartParser(nfa, evalExpressions.get(i));
	    	waitCycles = 0;
	    	try {
	    		while(!p.isFinished()) {
	    			// System.err.println("**Still running.**");
	    			if(waitCycles == 10)
	    				System.err.println("Warning: The NFA processor" +
	    						" threads have now been running for more" +
	    						" than five\nseconds on this string.  Under" +
	    						" normal circumstances (i.e., unless you've" +
	    						" given\nme a regex and/or string of" +
	    						" unusually horrendous length) this means" +
	    						" I've\nreached a deadlocked state.  Not to" +
	    						" worry, you can terminate this application" +
	    						"\n(hit Ctrl+C) and run again, and chances" +
	    						" are it won't happen again.  If it really" +
	    						"\nis just a more complex operation than" +
	    						" usual, just hang out here for a while.");
	    			Thread.sleep(500);
	    			waitCycles++;
	    		}
	    	} catch (InterruptedException ie) {
	    		System.err.println("I GOT INTERRUPTED!!!! OH NOES");
	    	}
		    System.out.print("[" + (i+1) + "/" + evalExpressions.size() + "] "
		    		+ evalExpressions.get(i) + ": ");
	    	if(p.success()) {
	    		System.out.print("ACCEPTED.\n");
	    		successfulParses++;
	    	} else {
	    		System.out.print("REJECTED.\n");
	    	}
	    	NewStartParser.reset();
	    }
	    System.out.println("Processing complete.  " + successfulParses 
	    		+ " out of " + evalExpressions.size() 
	    		+ " input strings were successful.");
	    
  }
  
  
  /**
	 * The main method, called when the program is invoked from the shell.
	 * @param args An array of strings passed as arguments from the CLI
	 */
  public static void main(String[] args) {
    
    /* if the filename was not passed in, print an error and exit */
    if(args.length < 1) {
      System.err.println("Usage: java group24 <filename>");
      System.exit(1);
    }
    
    /* create a group24 object with the file path as an argument */
    group24 myGroup24 = new group24(args[0]);
    try {
    	myGroup24.runIt();
    } catch (UnparseableException ue) {
    	System.err.println(ue.getMessage());
    }
  }
  
}